package com.nova.bluetooth.manage;

import static com.dido.fastblelib.data.BleScanState.STATE_SCANNING;

import android.bluetooth.BluetoothGatt;
import android.util.Log;

import androidx.lifecycle.ViewModelProvider;

import com.dido.fastblelib.BleManager;
import com.dido.fastblelib.callback.BleGattCallback;
import com.dido.fastblelib.callback.BleNotifyCallback;
import com.dido.fastblelib.callback.BleScanCallback;
import com.dido.fastblelib.callback.BleWriteCallback;
import com.dido.fastblelib.data.BleDevice;
import com.dido.fastblelib.exception.BleException;
import com.dido.fastblelib.scan.BleScanRuleConfig;
import com.dido.fastblelib.utils.HexUtil;
import com.nova.bluetooth.MyApp;
import com.nova.bluetooth.base.DeviceMessageWrap;
import com.nova.bluetooth.helpUtils.BluetoothDataUtil;
import com.nova.bluetooth.helpUtils.EventBusUtil;
import com.nova.bluetooth.helpUtils.LogUtil;
import com.nova.bluetooth.helpUtils.MyDataCallback;
import com.nova.bluetooth.helpUtils.MyGattCallback;
import com.nova.bluetooth.helpUtils.MyScanCallback;
import com.nova.bluetooth.ui.bluetoothDemo.NovaBluetoothControlViewModel;

import java.util.List;

public class BluetoothHelper {
    private static final String TAG = BluetoothHelper.class.getSimpleName();
    private NovaBluetoothControlViewModel mViewModel;

    // TODO: 2025/2/23 协议定的UUID
    private static final String UUID_SERVICE = "0000f000-0000-1000-8000-00805f9b34fb";
    private static final String UUID_READ = "0000f002-0000-1000-8000-00805f9b34fb";
    private static final String UUID_WRITE = "0000f001-0000-1000-8000-00805f9b34fb";


//    private static final String UUID_SERVICE = "0000faa0-0000-1000-8000-00805f9b34fb";
//    private static final String UUID_READ = "0000faa2-0000-1000-8000-00805f9b34fb";
//    private static final String UUID_WRITE = "0000faa1-0000-1000-8000-00805f9b34fb";


    //test 测试使用的 UUID
//    private static final String UUID_SERVICE = "0000ff00-0000-1000-8000-00805f9b34fb";
//    private static final String UUID_READ = "0000ff01-0000-1000-8000-00805f9b34fb";
//    private static final String UUID_WRITE = "0000ff02-0000-1000-8000-00805f9b34fb";

    private static BleDevice mConnectedBleDevice;  //当前连接设备

    public boolean isConnected() {
        return mConnectedBleDevice != null;
    }

    public static BleDevice getmConnectedBleDevice() {
        return mConnectedBleDevice;
    }

    // 私有静态实例
    private static volatile BluetoothHelper instance;

    // 私有化构造函数
    private BluetoothHelper() {
        init();
    }

    private void init() {
        mViewModel = new ViewModelProvider(MyApp.getInstance()).get(NovaBluetoothControlViewModel.class);
        BleManager.getInstance().init(MyApp.getInstance());
        BleManager.getInstance()
                .setMaxConnectCount(1)  //连接一个即可
                .enableLog(true)
                .setReConnectCount(3, 10000)
                .setConnectOverTime(8000)
                .setOperateTimeout(8000);

    }

    // 提供公共静态方法获取实例
    public static BluetoothHelper getInstance() {
        if (instance == null) {
            synchronized (BluetoothHelper.class) {
                if (instance == null) {
                    instance = new BluetoothHelper();
                }
            }
        }
        return instance;
    }


    /*********************************蓝牙操作*************************************/


    public void setNameScanRuleEmpty() {
        BleScanRuleConfig scanRuleConfig = new BleScanRuleConfig.Builder()
                .setDeviceName(true, "")   // 只扫描指定广播名的设备，可选
                .setScanTimeOut(5000)              // 扫描超时时间，可选，默认10秒
                .build();
        BleManager.getInstance().initScanRule(scanRuleConfig);
    }

    /**
     * 精确按名字扫描
     */
    public void setNameScanRule(String name) {
        BleScanRuleConfig scanRuleConfig = new BleScanRuleConfig.Builder()
                .setDeviceName(false, name)   // 只扫描指定广播名的设备，可选
                .setScanTimeOut(5000)              // 扫描超时时间，可选，默认10秒
                .build();
        BleManager.getInstance().initScanRule(scanRuleConfig);
    }

    public void cancelScan() {
        if (BleManager.getInstance().getScanSate() == STATE_SCANNING) {
            BleManager.getInstance().cancelScan();
        }
    }


    public void startScanAll() {
        setNameScanRuleEmpty();
        startScan();
    }
    public void startScanByDeviceName(String name) {
        setNameScanRule(name);
        startScan();
    }

    private MyScanCallback mScanCallback;

    public void setScanCallback(MyScanCallback mScanCallback) {
        this.mScanCallback = mScanCallback;
    }

    public void cleanCallback() {
        mScanCallback = null;
        mGattCallback = null;
    }

    private void startScan() {
        cancelScan();//旧的扫描未结束，先取消

        BleManager.getInstance().scan(new BleScanCallback() {
            @Override
            public void onScanStarted(boolean success) {
                if (mScanCallback != null) {
                    mScanCallback.onScanStarted();
                }
            }

            @Override
            public void onLeScan(BleDevice bleDevice) {
                super.onLeScan(bleDevice);
            }

            @Override
            public void onScanning(BleDevice bleDevice) {
                LogUtil.d(TAG + " onScanning:" + bleDevice.getName() + "  " + HexUtil.encodeHexStr(bleDevice.getScanRecord()));
                if (mScanCallback != null) {
                    mScanCallback.onScanning(bleDevice);
                }
            }

            @Override
            public void onScanFinished(List<BleDevice> scanResultList) {
                if (mScanCallback != null) {
                    mScanCallback.onScanFinished(scanResultList);
                }
            }
        });
    }


    public void connect(BleDevice bleDevice) {
        if (bleDevice == null) return;
        cancelScan();
        BleManager.getInstance().connect(bleDevice, gattCallback);
    }

    private MyGattCallback mGattCallback;

    public void setGattCallback(MyGattCallback mGattCallback) {
        this.mGattCallback = mGattCallback;
    }

    public void cleanGattCallback() {
        mGattCallback = null;
    }
    private final BleGattCallback gattCallback = new BleGattCallback() {
        @Override
        public void onStartConnect() {
            if (mGattCallback != null) {
                mGattCallback.onStartConnect();
            }
            LogUtil.d(TAG + " onStartConnect");
        }

        @Override
        public void onConnectFail(BleDevice bleDevice, BleException exception) {
            LogUtil.d(TAG + " onConnectFail:" + exception.toString());
            if (mGattCallback != null) {
                mGattCallback.onConnectFail(bleDevice, exception);
            }
        }

        @Override
        public void onConnectSuccess(BleDevice bleDevice, BluetoothGatt gatt, int status) {
            mConnectedBleDevice = bleDevice;
            LogUtil.d(TAG + " onConnectSuccess");
            notifyByOnConnectSuccess();

            if (mGattCallback != null) {
                mGattCallback.onConnectSuccess(bleDevice, gatt, status);
            }
        }

        @Override
        public void onDisConnected(boolean isActiveDisConnected, BleDevice bleDevice, BluetoothGatt gatt, int status) {
            //清理设备信息，否则下次重连，可能无法打开 notify
            BleManager.getInstance().destroy();
            mConnectedBleDevice = null;
            LogUtil.d(TAG + " onDisConnected");
            mViewModel.isConnectedLiveData.setValue(false);
            EventBusUtil.postMessage(new DeviceMessageWrap(DeviceMessageWrap.ACTION_DEVICE_DISCONNECTED, bleDevice));

            if (mGattCallback != null) {
                mGattCallback.onDisConnected(isActiveDisConnected, bleDevice, gatt, status);
            }
        }
    };

    /**
     * 延时1.5s，避免连接成功后，立即开启通知容易失败
     */
    private void notifyByOnConnectSuccess() {
        new Thread(() -> {
            try {
                Thread.sleep(1500);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            notifyDevice();
        }).start();
    }


    public void disconnect() {
        if (mConnectedBleDevice == null) {
            LogUtil.e(TAG + " bleDevice is null");
            return;
        }
        BleManager.getInstance().disconnect(mConnectedBleDevice);
    }

    public void disconnectAllDevice() {
        BleManager.getInstance().disconnectAllDevice();
    }

    public void destroy() {
        cleanWriteCallback();
        cleanCallback();
        BleManager.getInstance().disconnectAllDevice();
        BleManager.getInstance().destroy();
    }


    /**
     * 发送蓝牙数据
     */
    public void sendByteArrayDataSafety(byte[] data) {
        if (mConnectedBleDevice == null) {
            LogUtil.e(TAG + " bleDevice is null");
            return;
        }
        BleManager.getInstance().writeToQueue(
                mConnectedBleDevice,
                UUID_SERVICE,
                UUID_WRITE,
                data,
                writeCallback);
    }

    /**
     * 发送蓝牙数据
     */
    public void sendDataSafety(String hexString, boolean verify) {
        if (hexString.isEmpty() || hexString.length() % 2 != 0) {
            LogUtil.e(TAG + " sendData" + "数据未通过验证，不发送");
            return;
        }

        if (mConnectedBleDevice == null) {
            LogUtil.e(TAG + " bleDevice is null");
            return;
        }

        if (verify) {
            hexString = hexString + BluetoothDataUtil.CheckSum(
                    HexUtil.hexStringToBytes(hexString));
        }

        BleManager.getInstance().writeToQueue(
                mConnectedBleDevice,
                UUID_SERVICE,
                UUID_WRITE,
                HexUtil.hexStringToBytes(hexString),
                writeCallback);
    }

    private MyDataCallback mWriteCallback;

    public void setWriteCallback(MyDataCallback writeCallback) {
        this.mWriteCallback = writeCallback;
    }

    public void cleanWriteCallback() {
        mWriteCallback = null;
    }

    private final BleWriteCallback writeCallback = new BleWriteCallback() {
        @Override
        public void onWriteSuccess(int current, int total, byte[] justWrite) {
            Log.d(TAG, "test==>发送成功:" + HexUtil.formatHexString(justWrite));
            mViewModel.setTestCMDResultFirst(justWrite); //指令测试：APP发送指令校验结果设置

            if (mWriteCallback != null) {
                mWriteCallback.onWriteSuccess(current, total, justWrite);
            }
        }

        @Override
        public void onWriteFailure(BleException exception) {
            Log.d(TAG, "发送失败。");

            if (mWriteCallback != null) {
                mWriteCallback.onWriteFailure(exception);
            }
        }
    };


    /****************************ble notify*****************************/
    public void notifyDevice() {
        if (mConnectedBleDevice == null) {
            LogUtil.e(TAG + " bleDevice is null");
            return;
        }

        BleManager.getInstance().notify(mConnectedBleDevice,
                UUID_SERVICE,
                UUID_READ,
                notifyCallback);
    }

    private void stopDeviceNotify() {
        if (mConnectedBleDevice == null) {
            LogUtil.e(TAG + " bleDevice is null");
            return;
        }
        BleManager.getInstance().stopNotify(
                mConnectedBleDevice,
                UUID_SERVICE,
                UUID_READ);
    }

    private int notifyCount = -1;
    private Thread notifyThread = null;
    private final BleNotifyCallback notifyCallback = new BleNotifyCallback() {
        @Override
        public void onNotifySuccess() {
            Log.d(TAG, TAG + "_test==> onNotifySuccess");
            notifyCount = -1;
            mViewModel.isConnectedLiveData.setValue(true);
            EventBusUtil.postMessage(new DeviceMessageWrap(DeviceMessageWrap.ACTION_DEVICE_CONNECTED, mConnectedBleDevice));


            if (mGattCallback != null) {
                mGattCallback.onConnectedNotifySuccess(mConnectedBleDevice);
            }
        }

        @Override
        public void onNotifyFailure(BleException exception) {
            Log.e(TAG, TAG + "_test==> onNotifyFailure");

            try {
                if (notifyThread == null || !notifyThread.isAlive()) {
                    notifyThread = new Thread(() -> {
                        try {
                            Thread.sleep(500);
                        } catch (InterruptedException e) {
                            LogUtil.e(e.toString());
                        }
                        if (notifyCount < 3) {  //失败就多尝试几次
                            notifyDevice();
                            notifyCount++;
                        }
                    });
                    notifyThread.start();
                }
            } catch (Exception e) {
                LogUtil.e(e.toString());
            }
        }

        @Override
        public void onCharacteristicChanged(byte[] data) {
            Log.d(TAG + "_test==> onCharacteristicChanged", "设备端返回数据：" + HexUtil.formatHexString(data));
            mViewModel.setTestCMDResultSecond(data); //指令测试：设备返回指令校验结果设置
            dealWithDeviceData(data);
            if (mWriteCallback != null) {
                mWriteCallback.onCharacteristicChanged(data);
            }
        }
    };

    /**
     * 设备返回数据处理
     *
     * @param data
     */
    private void dealWithDeviceData(byte[] data) {
        try {
            mViewModel.dealWithData(data);
        } catch (Exception e) {
            LogUtil.e(TAG + " dealWithDeviceData异常数据==>" + e.toString());
        }
    }
}
